package service

import (
	"context"
	"fmt"
	"google.golang.org/grpc"
	healthpb "google.golang.org/grpc/health/grpc_health_v1"
	"net/http"
	"os"
	"strings"
	"time"
)

func listServiceNode(serviceName string) {
	etcdServerUrls := getEtcdV3ServerURLs()
	serviceLB := newServiceLB(etcdServerUrls, serviceName)
	serviceConfigClient := newServiceConfigClient(serviceLB)
	var serviceConfigs map[string]*serviceConfig
	var err error
	serviceConfigs, err = serviceConfigClient.GetConfigs()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	fmt.Printf("service-name(%v) ==> node list\n", serviceName)
	for k, v := range serviceConfigs {
		fmt.Printf("%v  content：%+v\n", k, *v)
	}
}

func clearServiceNode(serviceName, sequence string) {
	if serviceName == "" {
		return
	}
	if sequence == "" {
		return
	}
	etcdServerUrls := getEtcdV3ServerURLs()
	serviceLB := newServiceLB(etcdServerUrls, serviceName)
	serviceConfigClient := newServiceConfigClient(serviceLB)
	var err error
	fmt.Printf("service-name(%v) ==> node clear\n", serviceName)
	err = serviceConfigClient.ClearConfig(sequence)
	if err != nil && err != ErrServiceConfigKeyNotExist {
		fmt.Fprintln(os.Stderr, fmt.Sprintf("%v %v clear err %v\n", serviceName, sequence, err))
	}
}

func pingServiceNode(serviceName, sequence string) {
	etcdServerUrls := getEtcdV3ServerURLs()
	serviceLB := newServiceLB(etcdServerUrls, serviceName)
	serviceConfigClient := newServiceConfigClient(serviceLB)
	var serviceConfigs map[string]*serviceConfig
	var err error
	serviceConfigs, err = serviceConfigClient.GetConfigs()
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	fmt.Printf("service-name(%v) ==> node ping\n", serviceName)
	for _, v := range serviceConfigs {
		if sequence != "" {
			if v.ServicePort != sequence {
				continue
			}
		}
		var addr string
		if v.ServiceIP != "" {
			addr = fmt.Sprintf("%v:%v", v.ServiceIP, v.ServicePort)
		} else {
			addr = fmt.Sprintf("%v:%v", serviceName, v.ServicePort)
		}
		switch strings.ToLower(v.ServiceKind) {
		case "rpc", "grpc":
			err := pingGrpcService(addr, serviceName)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				continue
			}
		case "http", "gin":
			err := pingHttpService(addr, serviceName)
			if err != nil {
				fmt.Fprintln(os.Stderr, err)
				continue
			}
		default:
			fmt.Fprintln(os.Stderr, "未知的服务类型")
			continue
		}
	}
}

func pingGrpcService(addr, serviceName string) error {
	ctx, cancel := context.WithTimeout(context.TODO(), 3*time.Second)
	defer cancel()
	conn, err := grpc.Dial(addr, grpc.WithInsecure())
	if err != nil {
		return err
	}
	resp, err := healthpb.NewHealthClient(conn).Check(ctx, &healthpb.HealthCheckRequest{Service: ""})
	if err != nil {
		return err
	}
	fmt.Printf("service-name(%v) addr(%v) response status：%v\n", serviceName, addr, resp.GetStatus())
	return nil
}

func pingHttpService(addr, serviceName string) error {
	target := fmt.Sprintf("http://%v", addr)
	req, err := http.NewRequest(http.MethodGet, target, nil)
	if err != nil {
		return err
	}
	response, err := http.DefaultClient.Do(req)
	if err != nil {
		return err
	}
	fmt.Printf("service-name(%v) addr(%v) response status %v\n", serviceName, target, response.StatusCode)
	return response.Body.Close()
}
